package com.yonyou.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonyou.constant.MailAddressConstant;
import com.yonyou.dao.OerSecCzzfdDao;
import com.yonyou.exception.ErrorMessageException;
import com.yonyou.mapper.OerSecCzzfdMapper;
import com.yonyou.model.OerSecCzzfMlid;
import com.yonyou.model.OerSecCzzfd;
import com.yonyou.model.OerYszb;
import com.yonyou.model.RequestEntity;
import com.yonyou.util.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @author: wangchu
 * @date: 2025-04-29 15:17
 * @description:
 */
@Slf4j
@Service
public class OerSecCzzfdServiceImpl extends ServiceImpl<OerSecCzzfdMapper, OerSecCzzfd> implements OerSecCzzfdService {

    @Autowired
    private OerSecCzzfdDao czzfdDao;

    @Value("${business.llm-url}")
    private String llmUrl;
    @Value("${business.llm-key}")
    private String llmKey;
    @Value("${business.llm-model}")
    private String llmModelName;
    @Autowired
    private MailService mailService;
    @Autowired
    private MailAddressConstant mailAddressConstant;

    /**
     * 整合数据
     */
    @Override
    public void startCombine() {
        log.info("【OER_SEC_CZZFD_TASK】start");
        // 查询触发器结果的待支付单据
        List<OerSecCzzfMlid> mlids = czzfdDao.searchNewNote();
        log.info("【OER_SEC_CZZFD_TASK】查询到待支付单据目录信息: {}", JSONUtil.toJsonStr(mlids));
        // 待保存集合
        List<OerSecCzzfd> saveList = new ArrayList<>();
        // 查询待支付单据信息
        for (OerSecCzzfMlid  mlid : mlids) {
            try {
                // 查询明细
                log.info("【OER_SEC_CZZFD_TASK】开始查询明细: {}", JSONUtil.toJsonStr(mlid));
                List<OerSecCzzfd> czzfds = czzfdDao.searchNewCzzfd(mlid);
                if (CollUtil.isEmpty(czzfds)) {
                    log.error("【OER_SEC_CZZFD_TASK】明细为空！");
                    continue;
                }
                log.info("【OER_SEC_CZZFD_TASK】查询结果: {}", JSONUtil.toJsonStr(czzfds));
                // 查询指标
                List<OerYszb> yszbs = czzfdDao.searchYszb(mlid);
                if (CollUtil.isEmpty(yszbs)) {
                    log.error("【OER_SEC_CZZFD_TASK】U8指标为空！");
                    continue;
                }
                // 四种情况
                if (czzfds.size() == 1 && yszbs.size() == 1) {
                    log.info("【OER_SEC_CZZFD_TASK】结算方式与指标都仅为1条！");
                    OerSecCzzfd czzfd = czzfds.get(0);
                    OerYszb yszb = yszbs.get(0);
                    if (BigDecimal.valueOf(czzfd.getJsje()).compareTo(BigDecimal.valueOf(yszb.getZbzyje())) != 0) {
                        log.error("【OER_SEC_CZZFD_TASK】结算方式与指标都仅为1条时，结算方式金额不等于指标金额！");
                        continue;
                    }
                    // 实付金额
                    OerSecCzzfd sfje_1_1 = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                    sfje_1_1.setZbid(yszb.getZbid())
                            .setZbzy(yszb.getZbzy())
                            .setDjzbzy(yszb.getDjzbzy())
                            .setXmdm(yszb.getXmdm())
                            .setXmmc(yszb.getXmmc())
                            .setYsxmdm(yszb.getYsxmdm())
                            .setYsxmmc(yszb.getYsxmmc())
                            .setZjxzdm(yszb.getZjxzdm())
                            .setZjxzmc(yszb.getZjxzmc())
                            .setWhdm(yszb.getWhdm())
                            .setWhmc(yszb.getWhmc())
                            .setZbzyje(yszb.getZbzyje())
                            .setZfje(czzfd.getJsje() - czzfd.getSds())
                            .setZjwldx(StrUtil.isBlank(czzfd.getGrdm()) ? "19-与部门外其他" : "24-与部门内其他");
                    saveList.add(sfje_1_1);
                    // 税额
                    if (czzfd.getSds() > 0) {
                        OerSecCzzfd tax_1_1 = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                        tax_1_1.setZbid(yszb.getZbid())
                                .setZbzy(yszb.getZbzy())
                                .setDjzbzy(yszb.getDjzbzy())
                                .setXmdm(yszb.getXmdm())
                                .setXmmc(yszb.getXmmc())
                                .setYsxmdm(yszb.getYsxmdm())
                                .setYsxmmc(yszb.getYsxmmc())
                                .setZjxzdm(yszb.getZjxzdm())
                                .setZjxzmc(yszb.getZjxzmc())
                                .setWhdm(yszb.getWhdm())
                                .setWhmc(yszb.getWhmc())
                                .setZbzyje(yszb.getZbzyje())
                                .setZfje(czzfd.getSds())
                                .setYhzh("29412001040004160")
                                .setKhyh("农行固原分行营业部")
                                .setSkr("宁夏师范大学")
                                .setZjwldx("24-与部门内其他");
                        saveList.add(tax_1_1);
                    }
                } else if (czzfds.size() == 1 && yszbs.size() > 1) {
                    log.info("【OER_SEC_CZZFD_TASK】结算方式为1条，指标为多条！以指标占用金额为准，生成多条支付单！");
                    OerSecCzzfd czzfd = czzfds.get(0);
                    // 实付金额
                    for (OerYszb yszb : yszbs) {
                        OerSecCzzfd sfje_1_n = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                        sfje_1_n.setZbid(yszb.getZbid())
                                .setZbzy(yszb.getZbzy())
                                .setDjzbzy(yszb.getDjzbzy())
                                .setXmdm(yszb.getXmdm())
                                .setXmmc(yszb.getXmmc())
                                .setYsxmdm(yszb.getYsxmdm())
                                .setYsxmmc(yszb.getYsxmmc())
                                .setZjxzdm(yszb.getZjxzdm())
                                .setZjxzmc(yszb.getZjxzmc())
                                .setWhdm(yszb.getWhdm())
                                .setWhmc(yszb.getWhmc())
                                .setZbzyje(yszb.getZbzyje())
                                .setZfje(new BigDecimal(Double.toString((yszb.getZbzyje() / czzfd.getJsje()) * (czzfd.getJsje() - czzfd.getSds())))
                                                .setScale(2, RoundingMode.HALF_UP)
                                                .doubleValue())
                                .setZjwldx(StrUtil.isBlank(czzfd.getGrdm()) ? "19-与部门外其他" : "24-与部门内其他");
                        saveList.add(sfje_1_n);
                    }
                    // 税额
                    if (czzfd.getSds() > 0){
                        for (OerYszb yszb : yszbs) {
                            OerSecCzzfd tax_1_n = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                            tax_1_n.setZbid(yszb.getZbid())
                                    .setZbzy(yszb.getZbzy())
                                    .setDjzbzy(yszb.getDjzbzy())
                                    .setXmdm(yszb.getXmdm())
                                    .setXmmc(yszb.getXmmc())
                                    .setYsxmdm(yszb.getYsxmdm())
                                    .setYsxmmc(yszb.getYsxmmc())
                                    .setZjxzdm(yszb.getZjxzdm())
                                    .setZjxzmc(yszb.getZjxzmc())
                                    .setWhdm(yszb.getWhdm())
                                    .setWhmc(yszb.getWhmc())
                                    .setZbzyje(yszb.getZbzyje())
                                    .setZfje(new BigDecimal(Double.toString((yszb.getZbzyje() / czzfd.getJsje()) * czzfd.getSds()))
                                            .setScale(2, RoundingMode.HALF_UP)
                                            .doubleValue())
                                    .setYhzh("29412001040004160")
                                    .setKhyh("农行固原分行营业部")
                                    .setSkr("宁夏师范大学")
                                    .setZjwldx("24-与部门内其他");
                            saveList.add(tax_1_n);
                        }
                    }
                } else if (czzfds.size() > 1 && yszbs.size() == 1) {
                    log.info("【OER_SEC_CZZFD_TASK】结算方式为多条，指标为1条！以结算金额-税为准，生成多条支付单！");
                    OerYszb yszb = yszbs.get(0);
                    // 实付金额
                    for (OerSecCzzfd czzfd : czzfds) {
                        czzfd.setZbid(yszb.getZbid())
                                .setZbzy(yszb.getZbzy())
                                .setDjzbzy(yszb.getDjzbzy())
                                .setXmdm(yszb.getXmdm())
                                .setXmmc(yszb.getXmmc())
                                .setYsxmdm(yszb.getYsxmdm())
                                .setYsxmmc(yszb.getYsxmmc())
                                .setZjxzdm(yszb.getZjxzdm())
                                .setZjxzmc(yszb.getZjxzmc())
                                .setWhdm(yszb.getWhdm())
                                .setWhmc(yszb.getWhmc())
                                .setZbzyje(yszb.getZbzyje())
                                .setZfje(czzfd.getJsje() - czzfd.getSds())
                                .setZjwldx(StrUtil.isBlank(czzfd.getGrdm()) ? "19-与部门外其他" : "24-与部门内其他");
                        saveList.add(czzfd);
                    }
                    // 税额汇总处理
                    double totalSds = 0.0;
                    OerSecCzzfd tax_n_1 = BeanUtil.copyProperties(czzfds.get(0), OerSecCzzfd.class);
                    for (OerSecCzzfd czzfd : czzfds) {
                        totalSds += czzfd.getSds();
                    }
                    if (totalSds > 0){
                        tax_n_1.setZbid(yszb.getZbid())
                                .setZbzy(yszb.getZbzy())
                                .setDjzbzy(yszb.getDjzbzy())
                                .setXmdm(yszb.getXmdm())
                                .setXmmc(yszb.getXmmc())
                                .setYsxmdm(yszb.getYsxmdm())
                                .setYsxmmc(yszb.getYsxmmc())
                                .setZjxzdm(yszb.getZjxzdm())
                                .setZjxzmc(yszb.getZjxzmc())
                                .setWhdm(yszb.getWhdm())
                                .setWhmc(yszb.getWhmc())
                                .setZbzyje(yszb.getZbzyje())
                                .setZfje(totalSds)
                                .setYhzh("29412001040004160")
                                .setKhyh("农行固原分行营业部")
                                .setSkr("宁夏师范大学")
                                .setZjwldx("24-与部门内其他");
                        saveList.add(tax_n_1);
                    }
                } else {
                    if (String.valueOf(mlid.getDjlxid()).equals("160") &&
                            (czzfds.stream().anyMatch(czzf -> czzf.getFymx().contains("社会保障费")) ||
                            czzfds.stream().anyMatch(czzf -> czzf.getZy().contains("增值税")))) {
                        log.info("【OER_SEC_CZZFD_TASK】明细为多条，指标为多条！社保缴费、增值税");
                        // 数据校验：指标条数=结算条数，金额对应
                        // 创建可修改的副本列表
                        List<OerSecCzzfd> availableCzzfds = new ArrayList<>(czzfds);
                        boolean valid = true;

                        // 校验条数是否相等
                        if (yszbs.size() != czzfds.size()) {
                            log.error("【OER_SEC_CZZFD_TASK】社保缴费、增值税场景下指标条数与结算条数不相等！指标数:{}，结算数:{}", yszbs.size(), czzfds.size());
                            valid = false;
                        }
                        // 如果条数相等，继续校验金额是否能一一对应
                        if (valid) {
                            // 创建金额映射用于校验
                            Map<Double, Integer> yszbAmountCount = new HashMap<>();
                            Map<Double, Integer> czzfdAmountCount = new HashMap<>();

                            // 统计yszbs中各金额的数量
                            for (OerYszb yszb : yszbs) {
                                Double amount = yszb.getZbzyje();
                                yszbAmountCount.put(amount, yszbAmountCount.getOrDefault(amount, 0) + 1);
                            }

                            // 统计czzfds中各金额的数量
                            for (OerSecCzzfd czzfd : czzfds) {
                                Double amount = czzfd.getJsje();
                                czzfdAmountCount.put(amount, czzfdAmountCount.getOrDefault(amount, 0) + 1);
                            }

                            // 校验金额分布是否一致
                            if (!yszbAmountCount.equals(czzfdAmountCount)) {
                                log.error("【OER_SEC_CZZFD_TASK】社保缴费、增值税场景下指标金额与结算金额无法一一对应！指标金额分布:{}，结算金额分布:{}",
                                        yszbAmountCount, czzfdAmountCount);
                                valid = false;
                            }
                        }

                        // 如果数据校验通过，进行匹配处理
                        if (valid) {
                            for (OerYszb yszb : yszbs) {
                                Iterator<OerSecCzzfd> iterator = availableCzzfds.iterator();
                                while (iterator.hasNext()) {
                                    OerSecCzzfd czzfd = iterator.next();
                                    if (BigDecimal.valueOf(yszb.getZbzyje()).compareTo(BigDecimal.valueOf(czzfd.getJsje())) == 0) {
                                        OerSecCzzfd sb_gz_n_n = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                                        if (yszb.getZbzyje() != 0 && czzfd.getJsje() != 0) {
                                            sb_gz_n_n.setZbid(yszb.getZbid())
                                                    .setZbzy(yszb.getZbzy())
                                                    .setDjzbzy(yszb.getZbzy())
                                                    .setNrzy(czzfd.getNrzy())
                                                    .setXmdm(yszb.getXmdm())
                                                    .setXmmc(yszb.getXmmc())
                                                    .setYsxmdm(yszb.getYsxmdm())
                                                    .setYsxmmc(yszb.getYsxmmc())
                                                    .setZjxzdm(yszb.getZjxzdm())
                                                    .setZjxzmc(yszb.getZjxzmc())
                                                    .setWhdm(yszb.getWhdm())
                                                    .setWhmc(yszb.getWhmc())
                                                    .setZbzyje(yszb.getZbzyje())
                                                    .setZfje(yszb.getZbzyje())
                                                    .setYhzh(czzfd.getYhzh())
                                                    .setKhyh(czzfd.getKhyh())
                                                    .setSkr(czzfd.getSkr())
                                                    .setZjwldx("24-与部门内其他");
                                            saveList.add(sb_gz_n_n);
                                        }
                                        // 匹配成功后，从可用列表中移除此czzfd，避免重复使用
                                        iterator.remove();
                                        break;
                                    }
                                }
                            }
                        }
                    } else if (String.valueOf(mlid.getDjlxid()).startsWith("9")) {
                        log.info("【OER_SEC_CZZFD_TASK】结算方式为多条，指标为多条！其他收入手工对应！");
                        BigDecimal ysSum = BigDecimal.ZERO;
                        BigDecimal jsSum = BigDecimal.ZERO;
                        for (OerYszb yszb : yszbs) {
                            ysSum = ysSum.add(BigDecimal.valueOf(yszb.getZbzyje()));
                        }
                        for (OerSecCzzfd czzfd : czzfds) {
                            jsSum = jsSum.add(BigDecimal.valueOf(czzfd.getJsje()));
                        }
                        if (ysSum.compareTo(jsSum) != 0) {
                            log.error("【OER_SEC_CZZFD_TASK】结算方式为多条，指标为多条！其他收入校验结算方式总额与指标总额不符！");
                            continue;
                        }

                        // 新增：存储每个指标对应的税额
                        Map<Integer, OerSecCzzfd> taxMap = new HashMap<>();

                        for (OerSecCzzfd czzfd : czzfds) {
                            for (OerYszb yszb : yszbs) {
                                double remainingJsje = czzfd.getJsje();
                                double sds = czzfd.getSds();

                                // 当前指标足够
                                if (BigDecimal.valueOf(yszb.getZbzyje()).compareTo(BigDecimal.valueOf(remainingJsje)) >= 0) {
                                    OerSecCzzfd nc = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                                    nc.setZbid(yszb.getZbid())
                                            .setZbzy(yszb.getZbzy())
                                            .setDjzbzy(yszb.getDjzbzy())
                                            .setXmdm(yszb.getXmdm())
                                            .setXmmc(yszb.getXmmc())
                                            .setYsxmdm(yszb.getYsxmdm())
                                            .setYsxmmc(yszb.getYsxmmc())
                                            .setZjxzdm(yszb.getZjxzdm())
                                            .setZjxzmc(yszb.getZjxzmc())
                                            .setWhdm(yszb.getWhdm())
                                            .setWhmc(yszb.getWhmc())
                                            .setZbzyje(yszb.getZbzyje())
                                            .setZfje(remainingJsje - sds)
                                            .setZjwldx(StrUtil.isBlank(czzfd.getGrdm()) ? "19-与部门外其他" : "24-与部门内其他");
                                    saveList.add(nc);

                                    // 更新指标占用金额
                                    yszb.setZbzyje(BigDecimal.valueOf(yszb.getZbzyje()).subtract(BigDecimal.valueOf(remainingJsje)).doubleValue());

                                    // 处理税额
                                    if (sds > 0) {
                                        if (!taxMap.containsKey(yszb.getZbid())) {
                                            OerSecCzzfd tax = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                                            tax.setZbid(yszb.getZbid())
                                                    .setZbzy(yszb.getZbzy())
                                                    .setDjzbzy(yszb.getDjzbzy())
                                                    .setXmdm(yszb.getXmdm())
                                                    .setXmmc(yszb.getXmmc())
                                                    .setYsxmdm(yszb.getYsxmdm())
                                                    .setYsxmmc(yszb.getYsxmmc())
                                                    .setZjxzdm(yszb.getZjxzdm())
                                                    .setZjxzmc(yszb.getZjxzmc())
                                                    .setWhdm(yszb.getWhdm())
                                                    .setWhmc(yszb.getWhmc())
                                                    .setZbzyje(yszb.getZbzyje())
                                                    .setZfje(sds)
                                                    .setYhzh("29412001040004160")
                                                    .setKhyh("农行固原分行营业部")
                                                    .setSkr("宁夏师范大学")
                                                    .setZjwldx("24-与部门内其他");
                                            taxMap.put(yszb.getZbid(), tax);
                                        } else {
                                            OerSecCzzfd tax = taxMap.get(yszb.getZbid());
                                            tax.setZfje(tax.getZfje() + sds);
                                        }
//                                        czzfd.setSds(BigDecimal.valueOf(czzfd.getSds()).subtract(BigDecimal.valueOf(sds)).doubleValue());
                                    }

                                    // 停止遍历指标
                                    break;
                                } else if (BigDecimal.valueOf(yszb.getZbzyje()).compareTo(BigDecimal.ZERO) > 0) {
                                    // 按比例分配
                                    double ratio = yszb.getZbzyje() / remainingJsje;
                                    OerSecCzzfd nc = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                                    nc.setZbid(yszb.getZbid())
                                            .setZbzy(yszb.getZbzy())
                                            .setDjzbzy(yszb.getDjzbzy())
                                            .setXmdm(yszb.getXmdm())
                                            .setXmmc(yszb.getXmmc())
                                            .setYsxmdm(yszb.getYsxmdm())
                                            .setYsxmmc(yszb.getYsxmmc())
                                            .setZjxzdm(yszb.getZjxzdm())
                                            .setZjxzmc(yszb.getZjxzmc())
                                            .setWhdm(yszb.getWhdm())
                                            .setWhmc(yszb.getWhmc())
                                            .setZbzyje(yszb.getZbzyje())
                                            .setZfje(new BigDecimal(Double.toString((yszb.getZbzyje() / remainingJsje) * (remainingJsje - sds)))
                                                    .setScale(2, RoundingMode.HALF_UP)
                                                    .doubleValue())
                                            .setZjwldx(StrUtil.isBlank(czzfd.getGrdm()) ? "19-与部门外其他" : "24-与部门内其他");
                                    saveList.add(nc);

                                    // 更新结算金额和指标金额
                                    double allocatedAmount = yszb.getZbzyje();
                                    czzfd.setJsje(BigDecimal.valueOf(czzfd.getJsje()).subtract(BigDecimal.valueOf(allocatedAmount)).doubleValue());
                                    yszb.setZbzyje(0d);

                                    // 处理税额（按比例）
                                    if (sds > 0) {
                                        double allocatedTax = ratio * sds;
                                        if (!taxMap.containsKey(yszb.getZbid())) {
                                            OerSecCzzfd tax = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                                            tax.setZbid(yszb.getZbid())
                                                    .setZbzy(yszb.getZbzy())
                                                    .setDjzbzy(yszb.getDjzbzy())
                                                    .setXmdm(yszb.getXmdm())
                                                    .setXmmc(yszb.getXmmc())
                                                    .setYsxmdm(yszb.getYsxmdm())
                                                    .setYsxmmc(yszb.getYsxmmc())
                                                    .setZjxzdm(yszb.getZjxzdm())
                                                    .setZjxzmc(yszb.getZjxzmc())
                                                    .setWhdm(yszb.getWhdm())
                                                    .setWhmc(yszb.getWhmc())
                                                    .setZbzyje(yszb.getZbzyje())
                                                    .setZfje(allocatedTax)
                                                    .setYhzh("29412001040004160")
                                                    .setKhyh("农行固原分行营业部")
                                                    .setSkr("宁夏师范大学")
                                                    .setZjwldx("24-与部门内其他");
                                            taxMap.put(yszb.getZbid(), tax);
                                        } else {
                                            OerSecCzzfd tax = taxMap.get(yszb.getZbid());
                                            tax.setZfje(tax.getZfje() + allocatedTax);
                                        }
                                        czzfd.setSds(BigDecimal.valueOf(czzfd.getSds()).subtract(BigDecimal.valueOf(allocatedTax)).doubleValue());
                                    }
                                }
                            }
                        }

                        // 添加所有税额对象到保存列表
                        for (OerSecCzzfd tax : taxMap.values()) {
                            if (tax.getZfje() > 0) {
                                saveList.add(tax);
                            }
                        }

                } else {
                        log.info("【OER_SEC_CZZFD_TASK】结算方式为多条，指标为多条！大模型判断该如何对应！");
                        List<Map<String, Object>> jsList = new ArrayList<>();
                        BigDecimal totalJsje = BigDecimal.ZERO;

                        for (int i = 0; i < czzfds.size(); i++) {
                            OerSecCzzfd czzfd = czzfds.get(i);
                            Map<String, Object> js = new HashMap<>();
                            js.put("结算方式编号", i);
                            js.put("结算方式", czzfd.getJsfsmc());
                            js.put("结算金额", czzfd.getJsje());
                            js.put("用途", czzfd.getJsbz());
                            jsList.add(js);
                            totalJsje = totalJsje.add(BigDecimal.valueOf(czzfd.getJsje()));
                        }

                        List<Map<String, Object>> ysList = new ArrayList<>();
                        Map<Integer, OerYszb> ysMap = new HashMap<>(16);
                        Map<Integer, Map<String, Object>> ysListMap = new HashMap<>(); // 用于合并相同指标ID的数据
                        BigDecimal totalZbzyje = BigDecimal.ZERO;

                        for (int i = 0; i < yszbs.size(); i++) {
                            OerYszb yszb = yszbs.get(i);

                            // 如果该指标ID已存在，则合并余额
                            if (ysListMap.containsKey(yszb.getZbid())) {
                                Map<String, Object> existingYs = ysListMap.get(yszb.getZbid());
                                Double currentBalance = (Double) existingYs.get("可用余额");
                                existingYs.put("可用余额", currentBalance + yszb.getZbzyje());
                            } else {
                                // 如果是新指标ID，创建新条目
                                Map<String, Object> ys = new HashMap<>();
                                ys.put("指标ID", yszb.getZbid());
                                ys.put("预算项目", yszb.getXmmc());
                                ys.put("财政资金性质", yszb.getZjxzmc());
                                ys.put("指标摘要", yszb.getZbzy());
                                ys.put("可用余额", yszb.getZbzyje());
                                ysListMap.put(yszb.getZbid(), ys);
                                ysMap.put(yszb.getZbid(), yszb); // 保留一个实例用于后续处理
                            }
                        }
                        // 将合并后的数据添加到ysList中
                        for (Map<String, Object> ys : ysListMap.values()) {
                            ysList.add(ys);
                            totalZbzyje = totalZbzyje.add(BigDecimal.valueOf((Double) ys.get("可用余额")));
                        }

                        StringBuilder prompt = new StringBuilder()
                                .append("你是一个财务出纳会计专家，负责根据结算方式从给定指标中挑选用来支付的指标，必须严格遵守以下规则：\n")
                                .append("1. 所有结算方式的总结算金额与所选指标的总划拨金额必须完全一致。\n")
                                .append("2. 每个指标的划拨金额不能超过其可用余额。\n")
                                .append("3. 一个结算方式可以使用多个指标组合支付，一个指标也可以用于多个结算方式，但总划拨金额不得超过该指标的可用余额。\n")
                                .append("4. 每个结算方式的划拨金额必须>0，总划拨金额不能超过所有指标的可用余额").append(totalZbzyje).append("。")
//                                .append("5. 输出格式必须为JSON数组，包含分析过程。示例为：")
                                .append("5. 输出格式必须为JSON数组，请严格按照此格式输出，不包含任何其他内容（如分析过程、解释等）。示例为：")
                                .append("[{\"结算方式编号\": 0, \"对应指标信息\": [{\"指标ID\": 3, \"划拨金额\": 100}]}]。")
                                .append("以下是详细数据：\n")
                                .append("结算方式及金额信息为：").append(JSONUtil.toJsonStr(jsList)).append("。\n")
                                .append("可选预算指标及金额为：").append(JSONUtil.toJsonStr(ysList)).append("。\n");
                        Map<String, Object> param = new HashMap<>(16);
                        param.put("model", llmModelName);
                        param.put(
                                "messages",
                                new ArrayList<Map<String, Object>>() {{
                                    add(
                                            new HashMap<String, Object>(16) {{
                                                put("role", "user");
                                                put("content", prompt.toString());
                                            }}
                                    );
                                }}
                        );
                        param.put("stream", false);
                        String params = JSONUtil.toJsonStr(param);
                        log.info("【OER_SEC_CZZFD_TASK】请求大模型分配指标与结算金额: {}", params);
                        JSONArray ra = null;
                        int times = 1;
                        while (true) {
                            String rs = HttpRequest.post(llmUrl)
                                    .header("Content-Type", "application/json")
                                    .header("Authorization", llmKey)
                                    .body(params)
                                    .timeout(120000)
                                    .setReadTimeout(120000)
                                    .execute()
                                    .body();
                            log.info("rs: {}", rs);
                            String answer = JSONUtil.parseObj(JSONUtil.parseObj(rs).getJSONArray("choices").get(0)).getJSONObject("message").getStr("content");
                            answer = answer.substring(answer.indexOf("["), answer.lastIndexOf("]")) + "]";
                            if (JSONUtil.isJsonArray(answer)) {
                                JSONArray tempRa = JSONUtil.parseArray(answer);

                                // 验证划拨金额总和是否等于结算金额总和
                                BigDecimal totalAmount = BigDecimal.ZERO;
                                for (Object o : tempRa) {
                                    JSONObject item = JSONUtil.parseObj(o);
                                    JSONArray dyzbxx = item.getJSONArray("对应指标信息");
//                                    totalAmount = totalAmount.add(BigDecimal.valueOf(item.getDouble("划拨金额")));
                                    if (dyzbxx != null) {
                                        for (Object zbObj : dyzbxx) {
                                            JSONObject zbItem = JSONUtil.parseObj(zbObj);
                                            Double hbje = zbItem.getDouble("划拨金额");
                                            if (hbje != null) {
                                                totalAmount = totalAmount.add(BigDecimal.valueOf(hbje));
                                            }
                                        }
                                    }
                                }
                                if (totalAmount.compareTo(totalJsje) == 0) {
                                    ra = tempRa;
                                    break;
                                } else {
                                    log.warn("【OER_SEC_CZZFD_TASK】第{}次尝试，划拨金额总和{}不等于结算金额总和{}", times, totalAmount, totalJsje);
                                }

                            }
                            times++;
                            if (times > 3) {
                                break;
                            }
                        }
                        if (Objects.nonNull(ra)) {
                            for (int i = 0; i < ra.size(); i++) {
                                JSONObject ro = JSONUtil.parseObj(ra.get(i));
                                int jsIndes = ro.getInt("结算方式编号");
                                OerSecCzzfd czzfd = czzfds.get(jsIndes);
                                JSONArray ya = ro.getJSONArray("对应指标信息");
                                for (Object o : ya) {
                                    JSONObject yo = JSONUtil.parseObj(o);
                                    OerSecCzzfd nc = BeanUtil.copyProperties(czzfd, OerSecCzzfd.class);
                                    Integer zbid = yo.getInt("指标ID");
                                    OerYszb yszb = ysMap.get(zbid);
                                    Double zfje = yo.getDouble("划拨金额");
                                    nc.setZbid(yszb.getZbid())
                                            .setZbzy(yszb.getZbzy())
                                            .setDjzbzy(yszb.getDjzbzy())
                                            .setXmdm(yszb.getXmdm())
                                            .setXmmc(yszb.getXmmc())
                                            .setYsxmdm(yszb.getYsxmdm())
                                            .setYsxmmc(yszb.getYsxmmc())
                                            .setZjxzdm(yszb.getZjxzdm())
                                            .setZjxzmc(yszb.getZjxzmc())
                                            .setWhdm(yszb.getWhdm())
                                            .setWhmc(yszb.getWhmc())
                                            .setZbzyje(yszb.getZbzyje())
                                            .setZfje(zfje)
                                            .setZjwldx(StrUtil.isBlank(czzfd.getGrdm()) ? "19-与部门外其他" : "24-与部门内其他");
                                    saveList.add(nc);
                                }
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                log.error("【OER_SEC_CZZFD_TASK】遍历待支付单据出现异常！", ex);
            }
        }

        // 判断支付单据类型
        Iterator<OerSecCzzfd> iterator = saveList.iterator();
        while (iterator.hasNext()) {
            OerSecCzzfd czzfd = iterator.next();
            czzfd.setZfzt(0);
            String nrzy = czzfd.getNrzy();
            boolean isZjxz1 = czzfd.getZjxzdm().startsWith("1");
            boolean isSbjf = czzfd.getDjlxid().equals(160) && StrUtil.isNotBlank(nrzy) && nrzy.startsWith("在编") &&
                    (nrzy.contains("基本医疗保险") || nrzy.contains("公务员医疗补助") || nrzy.contains("养老保险") || nrzy.contains("职业年金") || nrzy.contains("失业保险") || nrzy.contains("工伤保险"));
            boolean isZzs = czzfd.getDjlxid().equals(160) && czzfd.getZy().contains("增值税");
            if (isZjxz1 && !isSbjf && !isZzs) {
                // 国库集中支付
                boolean hasYhkh = StrUtil.isNotBlank(czzfd.getYhzh());
                boolean hasGwkh = StrUtil.isNotBlank(czzfd.getGwkh());
                boolean yhkhStartsWith6282 = hasYhkh && "6282".equals(StrUtil.subWithLength(czzfd.getYhzh(), 0, 4));
                boolean gwkhStartsWith6282 = hasGwkh && "6282".equals(StrUtil.subWithLength(czzfd.getGwkh(), 0, 4));
                if (BigDecimal.valueOf(czzfd.getZfje()).compareTo(BigDecimal.valueOf(2000000)) < 0 && czzfd.getSfzfcg() == 0 &&
                        (
                            // 情况1：有且仅有一个字段有值，并且不以 "6282" 开头
                            ((hasYhkh ^ hasGwkh) && !yhkhStartsWith6282 && !gwkhStartsWith6282)
                                ||
                            // 情况2：两个字段都有值，并且都不以 "6282" 开头
                            (hasYhkh && hasGwkh && !yhkhStartsWith6282 && !gwkhStartsWith6282)
                                ||
                            // 情况3：两个都有值且只有一个以6282开头且是转账
                            (hasYhkh && hasGwkh && (yhkhStartsWith6282 ^ gwkhStartsWith6282) && "转账".equals(czzfd.getJsfsmc()))
                        )
                ) {
                    czzfd.setZfdjlx("一般支付申请");
                } else if (
                        BigDecimal.valueOf(czzfd.getZfje()).compareTo(BigDecimal.valueOf(2000000)) >= 0
                                && czzfd.getSfzfcg() == 0
                ) {
                    czzfd.setZfdjlx("财政支付申请");
                } else if (
                        czzfd.getSfzfcg() == 1 && "政府采购".equals(czzfd.getZfcgfs())
                ) {
                    czzfd.setZfdjlx("政府采购申请无指标");
                } else if (
                        czzfd.getSfzfcg() == 1 && "零星采购".equals(czzfd.getZfcgfs())
                ) {
                    czzfd.setZfdjlx("零星采购申请");
                } else if (
                        // 情况1：有且仅有一个字段有值，并且以 "6282" 开头
                        ((hasYhkh ^ hasGwkh) && (yhkhStartsWith6282 ^ gwkhStartsWith6282))
                            ||
                        // 情况2: 两个字段都有值，并且都以 "6282" 开头
                        (hasYhkh && hasGwkh && yhkhStartsWith6282 && gwkhStartsWith6282)
                            ||
                        // 情况3：两个字段都有值，并且结算方式是"公务卡"
                        (hasYhkh && hasGwkh && (yhkhStartsWith6282 ^ gwkhStartsWith6282) && "公务卡".equals(czzfd.getJsfsmc()))
                ) {
                    czzfd.setZfdjlx("公务卡申请");
                } else {
                    log.error("【OER_SEC_CZZFD_TASK】通过条件判断支付单据类型失败！{}", JSONUtil.toJsonStr(czzfd));
                    czzfd.setZfzt(2).setZfztbzxx("通过条件判断支付单据类型失败！");
                }
            } else if (czzfd.getZjxzdm().startsWith("3") || isSbjf || isZzs) {
                czzfd.setZfdjlx("支付申请");
            } else if (czzfd.getZjxzdm().startsWith("2")) {
                czzfd.setZfdjlx("教育收费申请");
            } else {
                log.error("【OER_SEC_CZZFD_TASK】通过资金性质判断支付单据类型失败！{}", JSONUtil.toJsonStr(czzfd));
                czzfd.setZfzt(2)
                        .setZfztbzxx("通过资金性质判断支付单据类型失败！");
            }
            // 查询支出功能代码 + 支出功能名称
            OerYszb result = czzfdDao.searchYszbZcgnfl(czzfd.getGsdm(), czzfd.getKjnd(), czzfd.getMlid(), czzfd.getZbid());
            String zfzcgnfl = "";
            if (result != null && result.getZbgnkmdm() != null && result.getZbgnkmmc() != null) {
                zfzcgnfl = result.getZbgnkmdm() +"-"+ result.getZbgnkmmc();
                czzfd.setZfzcgnfl(zfzcgnfl);
            }
        }
        // 处理用途
        for (OerSecCzzfd czzfd : saveList) {
            String zfdjlx = czzfd.getZfdjlx();
            Integer djlxid = czzfd.getDjlxid();
            String nrzy = czzfd.getNrzy();
            boolean isSbjf = czzfd.getDjlxid().equals(160) && StrUtil.isNotBlank(nrzy) && nrzy.startsWith("在编") &&
                    (nrzy.contains("基本医疗保险") || nrzy.contains("公务员医疗补助") || nrzy.contains("养老保险") || nrzy.contains("职业年金") || nrzy.contains("失业保险") || nrzy.contains("工伤保险") || nrzy.contains("大额医疗"));
            boolean isZzs = czzfd.getDjlxid().equals(160) && czzfd.getZy().contains("增值税");

            if ("支付申请".equals(zfdjlx) && !isSbjf && !isZzs) {
                String zy = czzfd.getZy();
                if (StrUtil.isNotBlank(zy)) {
                    StringBuilder prompt = new StringBuilder()
                            .append("你是一个财务专家，请根据提供的支付摘要内容，提取并精简出用途名称，要求：\n")
                            .append("1. 输出格式必须为\"xxx费\"的形式。\n")
                            .append("2. 只输出最终结果，不要包含任何分析过程或其他内容。\n")
                            .append("支付摘要内容为：").append(zy);

                    Map<String, Object> param = new HashMap<>(16);
                    param.put("model", llmModelName);
                    param.put(
                            "messages",
                            new ArrayList<Map<String, Object>>() {{
                                add(
                                        new HashMap<String, Object>(16) {{
                                            put("role", "user");
                                            put("content", prompt.toString());
                                        }}
                                );
                            }}
                    );
                    param.put("stream", false);
                    String params = JSONUtil.toJsonStr(param);
                    log.info("【OER_SEC_CZZFD_TASK】请求大模型分析用途: {}", params);

                    try {
                        String rs = HttpRequest.post(llmUrl)
                                .header("Content-Type", "application/json")
                                .header("Authorization", llmKey)
                                .body(params)
                                .timeout(120000)
                                .setReadTimeout(120000)
                                .execute()
                                .body();

                        log.info("【OER_SEC_CZZFD_TASK】大模型返回用途分析结果: {}", rs);
                        String purpose = JSONUtil.parseObj(JSONUtil.parseObj(rs).getJSONArray("choices").get(0))
                                .getJSONObject("message").getStr("content");

                        // 确保返回的用途以"费"结尾，且不包含其他内容
                        if (purpose.contains("费")) {
                            purpose = purpose.substring(0, purpose.indexOf("费") + 1);
                            czzfd.setPurpose(purpose);
                        }
                    } catch (Exception e) {
                        log.error("【OER_SEC_CZZFD_TASK】大模型分析用途失败: ", e);
                    }
                }
            }
        }

        // 保存单据
        czzfdDao.saveZfd(saveList, mlids);
        log.info("【OER_SEC_CZZFD_TASK】end");
    }

    /**
     * 查询待支付信息
     *
     * @return
     */
    @Override
    public List<OerSecCzzfd> searchPayInfos() {
        return czzfdDao.searchPayInfos();
    }

    /**
     * 匹配指标
     *
     * @param zfid
     * @param indexArray
     * @return
     */
    @Override
    public List<JSONObject> matchIndex(String zfid, JSONArray indexArray) {
        // 获取待支付信息
        OerSecCzzfd czzfd = czzfdDao.searchPayInfoById(zfid);
        // 根据资金性质、预算项目、指标文号、是否政府采购，支出功能分类 匹配财政指标信息，一阶段校验
        List<JSONObject> firstList = new ArrayList<>();
        for (Object o : indexArray) {
            JSONObject jo = JSONUtil.parseObj(o);
            String nrzy = czzfd.getNrzy();
            boolean isSbjf = czzfd.getDjlxid().equals(160) && StrUtil.isNotBlank(nrzy) && nrzy.startsWith("在编") &&
                    (nrzy.contains("基本医疗保险") || nrzy.contains("公务员医疗补助") || nrzy.contains("养老保险") || nrzy.contains("职业年金") || nrzy.contains("失业保险") || nrzy.contains("工伤保险"));
            if (isSbjf) {  // 社保缴费 U8财政指标 使用 一体化非财政指标支付
                String zbzy = jo.getStr("指标摘要");
                if (!zbzy.contains("银行流水") || !czzfd.getNrzy().contains(zbzy.substring(zbzy.indexOf("银行流水") + 4).replaceAll("[^\\u4e00-\\u9fa5]", ""))) continue;
            } else {
                // 1.资金性质匹配
                String zjxzFeature = (czzfd.getZjxzdm() + czzfd.getZjxzmc()).replaceAll("-", "");
                if (!zjxzFeature.equals(jo.getStr("资金性质").replaceAll("-", ""))) {
                    continue;
                }
                // 2.预算项目匹配
                String ysxmFeature = "640000" + czzfd.getYsxmdm();
                if (!jo.getStr("项目").startsWith(ysxmFeature)) {
                    continue;
                }
                // 3.指标文号匹配
                String zbwhFeature = czzfd.getWhmc()
                        .replaceAll("（", "")
                        .replaceAll("）", "")
                        .replaceAll("〔", "")
                        .replaceAll("〕", "")
                        .replaceAll("﹝", "")
                        .replaceAll("﹞", "")
                        .replaceAll("\\[", "")
                        .replaceAll("]", "");
                String zbwhString = jo.getStr("指标文号")
                        .replaceAll("（", "")
                        .replaceAll("）", "")
                        .replaceAll("〔", "")
                        .replaceAll("〕", "")
                        .replaceAll("﹝", "")
                        .replaceAll("﹞", "")
                        .replaceAll("\\[", "")
                        .replaceAll("]", "");
                if (!"零星采购申请".equals(czzfd.getZfdjlx())){
                    if (!zbwhFeature.equals(zbwhString)) {
                        continue;
                    }
                }

                // 4.是否政府采购
                String sfzfcg = String.valueOf(czzfd.getSfzfcg());
                if ("1".equals(sfzfcg) && !jo.getStr("是否包含政府采购").startsWith("1")) {
                    continue;
                } else if ("0".equals(sfzfcg) && !jo.getStr("是否包含政府采购").startsWith("2")) {
                    continue;
                }
                // 5.支出功能分类
                if (!czzfd.getZfzcgnfl().replaceAll("-", "").equals(jo.getStr("支出功能分类").replaceAll("-", ""))) {
                    continue;
                }
                // 6.1 特殊处理：专项费用——公务用车运行维护费的指标只使用一体化"公务用车运行维护费"
                if (czzfd.getZbzy().equals("公务用车运行维护费") != jo.getStr("部门经济分类").contains("公务用车运行维护费")) continue;
                if (czzfd.getZbzy().equals("公务接待费") != jo.getStr("部门经济分类").contains("公务接待费")) continue;
                if (czzfd.getZbzy().equals("出国（境）经费") != jo.getStr("部门经济分类").contains("因公出国（境）费用")) continue;
                // 6.2 特殊处理：综合经费-基本运转支出使用特定指标
                if (czzfd.getZbzy().equals("综合经费") && czzfd.getYsxmmc().endsWith("基本运转支出") &&
                        !(jo.getStr("部门经济分类").contains("办公费") ||
                            jo.getStr("部门经济分类").contains("印刷费") ||
                            jo.getStr("部门经济分类").contains("差旅费") ||
                            jo.getStr("部门经济分类").contains("会议费") ||
                            jo.getStr("部门经济分类").contains("培训费") ||
                            jo.getStr("部门经济分类").contains("劳务费") ||
                            jo.getStr("部门经济分类").contains("工会经费") ||
                            jo.getStr("部门经济分类").contains("其他商品和服务支出"))) continue;

                // 6.3 特殊处理：通勤车的指标只使用一体化"其他商品和服务支出"
                if (czzfd.getZbzy().contains("通勤车") && !jo.getStr("部门经济分类").contains("其他商品和服务支出")) continue;
                // 6.4 特殊处理:费用报销单中校外奖助学金使用其他商品和服务支出指标
                if (czzfd.getDjlxid().equals(160) && czzfd.getZy() != null && (czzfd.getZy().contains("奖学金") || czzfd.getZy().contains("助学金") || czzfd.getZy().contains("奖助学金")) && !jo.getStr("部门经济分类").contains("其他商品和服务支出")) {
                    continue;
                }
                // 6.5 特殊处理:费用报销单（基建经费）(166)｜指标文号：382｜两条指标只有原始金额不一样
                if (czzfd.getDjlxid().equals(166) && czzfd.getZbzy().contains("服务基础教育信息技术应用大楼") && Math.abs(jo.getDouble("原始金额") - 46189087.50) > 0.01){
                    continue;
                }
                if (czzfd.getDjlxid().equals(166) && czzfd.getZbzy().contains("田径运动场") &&  Math.abs(jo.getDouble("原始金额") - 23668110.00) > 0.01){
                    continue;
                }
                // 6.6 特殊处理：u8维修（护）费 物业管理费
                if (czzfd.getYsxmmc().contains("基本运转支出") && "维修（护）费".equals(czzfd.getZbzy()) && !jo.getStr("部门经济分类").contains("物业管理费")) continue;
                // 6.7 特殊处理：固定资产报销单 专用设备购置
                if (czzfd.getDjlxid().equals(182) && !jo.getStr("部门经济分类").contains("专用设备购置")) continue;
            }

            // 一阶段校验通过
            firstList.add(jo);
        }

        // 判断一阶段校验结果
        // 匹配指标为空，匹配失败！
        if (CollUtil.isEmpty(firstList)) {
            String errorMessage = zfid + "匹配指标失败！根据资金性质、预算项目、指标文号、是否政府采购、支出功能分类，匹配到的财政指标为空！";
            czzfdDao.fillFail(zfid, errorMessage);
            throw new ErrorMessageException(errorMessage);
        }
        // 唯一确定一条指标
        if (firstList.size() == 1) {
            // 余额不足
            if (firstList.get(0).getDouble("可用余额") < czzfd.getZfje()) {
                String errorMessage = zfid + "匹配指标失败！唯一确定一条指标，但可用余额不足！" + JSONUtil.toJsonStr(firstList.get(0));
                czzfdDao.fillFail(zfid, errorMessage);
                throw new ErrorMessageException(errorMessage);
            } else {
//                czzfdDao.fillSucc(zfid);
                // 在 firstList 的第一个元素中添加 "使用金额"
                JSONObject firstItem = firstList.get(0);
                firstItem.set("使用金额", czzfd.getZfje());
            }
            return firstList;
        } else {
            // 匹配到了多条指标，计算金额是否充足
            BigDecimal sum = BigDecimal.ZERO;
            for (JSONObject jo : firstList) {
                sum = sum.add(BigDecimal.valueOf(jo.getDouble("可用余额")));
            }
            if (sum.compareTo(BigDecimal.valueOf(czzfd.getZfje())) < 0) {
                String errorMessage = zfid + "匹配指标失败！一阶段匹配了多条指标，但可用之和余额不足！" + JSONUtil.toJsonStr(firstList);
                czzfdDao.fillFail(zfid, errorMessage);
                throw new ErrorMessageException(errorMessage);
            } else {
                // 进入AI匹配阶段
                // 整合支付单据参数
                Map<String, Object> czzfdParam = new HashMap<String, Object>() {{
                    put("单据类型名称", czzfd.getDjlxmc());
                    put("单据摘要", czzfd.getZy());
                    put("单据内容摘要", czzfd.getNrzy());
                    put("应付金额", czzfd.getZfje());
                    put("单据指标摘要", czzfd.getDjzbzy());
                    put("指标摘要", czzfd.getZbzy());
                    put("项目名称", czzfd.getXmmc());
                    put("预算项目名称", czzfd.getYsxmmc());
                }};
                // 整合一阶段财政指标参数
//                int indes = 1;
                Map<String, JSONObject> czzbMap = new HashMap<>();
                for (JSONObject jo : firstList) {
//                    jo.set("编号", indes);
                    czzbMap.put(jo.getStr("序号"), jo);
                    jo.remove("原始金额"); // 财政指标信息中删除"原始金额"(一阶段匹配中用到)
//                    indes++;
                }
                StringBuilder prompt = new StringBuilder()
                        .append("你是一个财务出纳会计专家，负责根据支付单据从给定指标中挑选用来支付的财政指标，必须严格遵守以下规则：\n")
                        .append("1. 确保所有选中指标的划拨金额总和必须精确等于应付金额 ").append(czzfd.getZfje()).append("，严禁多付或少付！\n")
                        .append("2. 当单个指标余额足够时，只能选择一个指标；只有当单个指标余额不足时，才可以组合多个相关指标，但总金额必须精确等于应付金额:").append(czzfd.getZfje()).append("\n")
                        .append("3. 当有多个指标余额足够支付全额时，除非'部门经济分类'与单据摘要中的费用内容直接对应，才能选择具体分类，否则必须选择'其他商品和服务支出'这类通用性分类。\n")
//                        .append("4. 输出格式必须为JSON数组，包含分析过程、解释等。\n")
                        .append("4. 输出格式必须为JSON数组，且仅输出JSON数组，不包含任何其他内容（如分析过程、解释等）。\n")
                        .append("5. 格式示例：[{\"财政指标序号\": 1, \"划拨金额\": 500}]。\n");

                // 不同支付单据类型添加对应的提示词，在筛选指标中晒出了下面的指标
//                if (czzfd.getZbzy().equals("综合经费") && czzfd.getYsxmmc().endsWith("基本运转支出")) {
//                    prompt.append("**特别注意：**\n")
//                            .append("优先根据\"单据类型名称\"从以下列表中选择最合适的进行支付，且仅能选择以下列表中的指标：\n")
//                            .append("['办公费','印刷费','差旅费','会议费','培训费','劳务费','工会经费','其他商品和服务支出']。\n")
//                            .append("当支付金额可以被单个指标覆盖时，必须选择最相关的一个指标，不得选择多个。\n");
//                }
                prompt.append("以下是详细数据：\n")
                        .append("支付单据信息为：").append(JSONUtil.toJsonStr(czzfdParam)).append("\n")
                        .append("财政指标及金额为：").append(JSONUtil.toJsonStr(firstList)).append("\n");

                Map<String, Object> param = new HashMap<>(16);
                param.put("model", llmModelName);
                param.put(
                        "messages",
                        new ArrayList<Map<String, Object>>() {{
                            add(
                                    new HashMap<String, Object>(16) {{
                                        put("role", "user");
                                        put("content", prompt.toString());
                                    }}
                            );
                        }}
                );
                param.put("stream", false);
                String params = JSONUtil.toJsonStr(param);
                log.info("【OER_SEC_CZZFD_TASK】请求大模型匹配财政指标与金额: {}", params);
                JSONArray ra = null;
                int times = 1;
                while (true) {
                    String rs = HttpRequest.post(llmUrl)
                            .header("Content-Type", "application/json")
                            .header("Authorization", llmKey)
                            .body(params)
                            .timeout(120000)
                            .setReadTimeout(120000)
                            .execute()
                            .body();
                    log.info("【OER_SEC_CZZFD_TASK】大模型返回信息: {}", rs);
                    String answer = JSONUtil.parseObj(JSONUtil.parseObj(rs).getJSONArray("choices").get(0)).getJSONObject("message").getStr("content");
                    answer = answer.substring(answer.indexOf("["), answer.lastIndexOf("]")) + "]";
//                    if (JSONUtil.isJsonArray(answer)) {
//                        ra = JSONUtil.parseArray(answer);
//                        break;
//                    }
                    if (JSONUtil.isJsonArray(answer)) {
                        JSONArray tempRa = JSONUtil.parseArray(answer);

                        // 验证划拨金额总和是否等于应付金额
                        BigDecimal totalAmount = BigDecimal.ZERO;
                        for (Object o : tempRa) {
                            JSONObject item = JSONUtil.parseObj(o);
                            totalAmount = totalAmount.add(BigDecimal.valueOf(item.getDouble("划拨金额")));
                        }

                        // 使用compareTo进行精确比较
                        if (totalAmount.compareTo(BigDecimal.valueOf(czzfd.getZfje())) == 0) {
                            ra = tempRa; // 验证通过，保存结果
                            break;
                        } else {
                            log.warn("【OER_SEC_CZZFD_TASK】第{}次尝试，划拨金额总和{}不等于应付金额{}", times, totalAmount, czzfd.getZfje());
                        }
                    }
                    times++;
                    if (times > 3) {
                        break;
                    }
                }
                // 匹配成功
                List<JSONObject> secondList = new ArrayList<>();
                if (Objects.nonNull(ra)) {
                    for (Object o : ra) {
                        JSONObject rao = JSONUtil.parseObj(o);
                        int jsIndes = rao.getInt("财政指标序号");
                        JSONObject jo = czzbMap.get(String.valueOf(jsIndes));
                        double zfje = rao.getDouble("划拨金额");
                        jo.set("使用金额", zfje);
                        secondList.add(jo);
                    }
//                    czzfdDao.fillSucc(zfid);
                    return secondList;
                } else {
                    // 大模型匹配失败
                    String errorMessage = zfid + "匹配指标失败！二阶段大模型匹配失败！";
                    czzfdDao.fillFail(zfid, errorMessage);
                    throw new ErrorMessageException(errorMessage);
                }
            }
        }
    }

    /**
     * 财政支付指标信息处理
     * @param zfid 支付ID
     * @param indexes 支付单用到的财政指标
     */
    @Override
    public void processAndSaveIndexMatch(String zfid, JSONArray indexes) {
        // 合并各个字段的值
        StringBuilder zbzy = new StringBuilder();        // 指标摘要
        StringBuilder bmjjfl = new StringBuilder();      // 部门经济分类
        StringBuilder zfjjfl = new StringBuilder();      // 政府经济分类
        StringBuilder zjxz = new StringBuilder();        // 资金性质
        StringBuilder zblx = new StringBuilder();        // 指标类型
        StringBuilder xm = new StringBuilder();          // 项目
        StringBuilder zbwh = new StringBuilder();        // 指标文号
        StringBuilder sfbhzfcg = new StringBuilder();    // 是否包含政府采购

        for (int i = 0; i < indexes.size(); i++) {
            JSONObject index = indexes.getJSONObject(i);

            if (i > 0) {
                zbzy.append(",");
                bmjjfl.append(",");
                zfjjfl.append(",");
                zjxz.append(",");
                zblx.append(",");
                xm.append(",");
                zbwh.append(",");
                sfbhzfcg.append(",");
            }

            zbzy.append(index.getStr("指标摘要"));
            bmjjfl.append(index.getStr("部门经济分类"));
            zfjjfl.append(index.getStr("政府经济分类"));
            zjxz.append(index.getStr("资金性质"));
            zblx.append(index.getStr("指标类型"));
            xm.append(index.getStr("项目"));
            zbwh.append(StrUtil.nullToEmpty(index.getStr("指标文号")));
            sfbhzfcg.append(StrUtil.nullToEmpty(index.getStr("是否包含政府采购")));
        }

        // 调用DAO方法更新数据
        czzfdDao.updateCzPayInfo(zfid, zbzy.toString(), bmjjfl.toString(), zfjjfl.toString(),
                zjxz.toString(), zblx.toString(), xm.toString(), zbwh.toString(), sfbhzfcg.toString());
    }


    @Override
    public void failMessage(RequestEntity entity) {
        // 发送邮件
        for (String s : mailAddressConstant.getMailReceiver()) {
            mailService.simpleMessage(s, "宁夏师范大学财政支付制单失败邮件通知（系统自动发送请勿回复）", entity.getFailReason());
        }
        // 标记错误
        String failReason = entity.getFailReason();
        int index = failReason.indexOf("原因");
        String FailModule = index != -1 ? failReason.substring(0, index) : failReason;
        czzfdDao.fillFail(entity.getZfid(), FailModule);
    }

    @Override
    public void successNote(RequestEntity entity) {
        czzfdDao.successNote(entity);
    }

    /**
     * 获取首页统计数据
     * @return
     */
    public JSONObject getDashboardData() {
        JSONObject result = new JSONObject();

        // 获取总盘支付看板数据
        JSONObject summaryData = czzfdDao.getPaymentSummary();
        result.set("summary", summaryData);

        // 获取明细统计看板数据（当月）
        JSONArray detailData = czzfdDao.getMonthlyPaymentDetails();
        result.set("details", detailData);

        // 获取30天支付趋势数据
        JSONArray trendData = czzfdDao.getPaymentTrendData();
        result.set("trend", trendData);

        return result;
    }

}